
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.znyj.cloud.device.constant.SysConstant;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Timer;
import java.util.zip.CRC32;


/**
 * Created by gaoliwei02 on 17/6/9.
 */
public class SingleDevice {

    private static final int READ_TIMEOUT = 1000000;
    private static final int HEARTBEAT_PERIOD = 30000;
    private static final int MAX_LINK = 1;
    private Socket clientSocket;

    private int msgHead;
    private int dataCrc;
    private int msgVersion;
    private int format;
    private int reserved;
    private int dataLength;
    private long errorCode;


    private String PackageType;
    private int id;

    public int test_makeCrc(byte[] bytes) {
        CRC32 test_crc32 = new CRC32();
        test_crc32.update(bytes);
        int result = (int) test_crc32.getValue();
        test_crc32.reset();
        return result;
    }

    public SingleDevice(int id) {
        this.id = id;
    }

    public void begin() throws IOException, InterruptedException {
        String s = "127.0.0.1";
        System.out.println("begin create links:" + MAX_LINK);
        clientSocket = new Socket();
        clientSocket.setKeepAlive(true);
        clientSocket.setTcpNoDelay(true);
        clientSocket.setSoTimeout(READ_TIMEOUT);
        clientSocket.setReceiveBufferSize(1024);
        clientSocket.connect(new InetSocketAddress(s, Integer.parseInt("9977")), READ_TIMEOUT);

        Timer timer1 = new Timer();
        timer1.schedule(new ReceiveMsgTimer(), 10, 100);

        Timer timer = new Timer();
        timer.schedule(new SendMsgTimer(), 100, HEARTBEAT_PERIOD);
        new SendMsgTimer();

//        while (true) {
//            byte[] bytein = new byte[1024];
//            int length = clientSocket.getInputStream().read(bytein);
//            if (length > 0) {
//                JSONObject payloadJson = Assemble(bytein);
//                System.out.println("id:" + id + " length:" + length + " payloadJson:" + payloadJson.toString());
//                parseMsg(payloadJson);
//            }
//        }

        //接收LOOP
    }

    public class ReceiveMsgTimer extends java.util.TimerTask {
        public void run() {
            InputStream in = null;
            try {
                in = clientSocket.getInputStream();
                byte[] bytein = new byte[1024];
                int length = in.read(bytein);
                if (length > 0) {
                    JSONObject payloadJson = Assemble(bytein);
                    System.out.println("id:" + id + " length:" + length + " payloadJson:" + payloadJson.toString());
                    parseMsg(payloadJson);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void parseMsg(JSONObject payloadJson) {
        PackageType = payloadJson.getString(SysConstant.REPORT_KEY.MSG_TYPE);
        switch (PackageType) {
            case SysConstant.PACKAGE_VALUE.CTRL_SENT: {
                //System.out.println("id:" + id + "task:" + payloadJson.toString());

                byte[] tmp = new byte[0];
                tmp = makeTaskMsg(payloadJson.getString(SysConstant.CTRL_KEY.DEVICE_ID),
                        payloadJson.getLong(SysConstant.CTRL_KEY.ORDER_ID),
                        payloadJson.getLong(SysConstant.CTRL_KEY.ORDER_CREATE_TIME));
                OutputStream out = null;

                try {
                    Thread.sleep(8000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                try {
                    out = clientSocket.getOutputStream();
                    out.write(tmp);
                    out.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                break;
            }


            case SysConstant.PACKAGE_VALUE.HEARTBEAT_RES_SENT: {
                System.out.println("report:" + payloadJson.toString());
                break;
            }
//            case SysConstant.PACKAGE_VALUE.UP_SENT: {
//                logger.info("deviceId:" + deviceId + "/Update pag:" + payloadJson.toString());
//
//
//                ByteBuf buf = makeUpRes();
//                byte[] tmp = new byte[buf.readableBytes()];
//                buf.getBytes(buf.readerIndex(), tmp);
//                OutputStream out = null;
//                try {
//                    out = clientSocket.getOutputStream();
//                    out.write(tmp);
//                    out.flush();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//                break;
//            }
        }
    }

    //对进来的数据进行装配 head + Json
    public JSONObject Assemble(byte[] buf) {
        errorCode = 0;
        msgHead = intToint(buf, 0);
        dataCrc = intToint(buf, 4);
        msgVersion = intToint(buf, 8);
        format = intToint(buf, 12);
        reserved = intToint(buf, 16);
        dataLength = intToint(buf, 20);

        //第一步：头标志必须相同
        if (msgHead == SysConstant.HEAD.PROTOCOL_HEAD) {

        } else {
            System.out.println("msgHead:{} not equal 0xcafebabe!" + msgHead);
            errorCode = -1;
        }
        JSONObject payloadJson = new JSONObject();
        //第四步：检查是JSON包还是二进制数据包
        if (format == SysConstant.HEAD.FORMAT_JSON) {
            byte[] newb = new byte[dataLength];
            System.arraycopy(buf, 24, newb, 0, dataLength);
            payloadJson = byte2Json(newb);
        } else {
            payloadJson = null;
        }
        return payloadJson;
    }


    public class SendMsgTimer extends java.util.TimerTask {
        public void run() {
            byte[] tmp = new byte[0];
            tmp = makeReportMsg();
            OutputStream out = null;
            try {
                out = clientSocket.getOutputStream();
                out.write(tmp);
                out.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /*
{"returnMsg":"ok","orderId":539,"deviceId":"868575021017977","reportTime":1503485158595}
{"orderId":540,"controlMsg":"opencdb","userId":"user3","deviceId":"112173402247"}
*/
    private byte[] makeTaskMsg(String devid, long orderId, long time) {
        JSONObject send_ctrl = new JSONObject();
        send_ctrl.put(SysConstant.CTRL_KEY.MSG_TYPE, "ctrl_res");
        send_ctrl.put(SysConstant.CTRL_KEY.IMEI, orderId);
        send_ctrl.put(SysConstant.CTRL_KEY.ORDER_ID, orderId);
        send_ctrl.put(SysConstant.CTRL_KEY.ORDER_CREATE_TIME, time);
        send_ctrl.put(SysConstant.CTRL_KEY.CS_MSG, "ok");

        String json_string = send_ctrl.toString();
        byte[] json_byte = new byte[0];
        try {
            json_byte = json_string.getBytes("ASCII");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        int crc = test_makeCrc(json_byte);
        byte[] head_byte = new byte[24];
        int cnt = 0;
        head_byte[cnt++] = (byte) 0xbe;
        head_byte[cnt++] = (byte) 0xba;
        head_byte[cnt++] = (byte) 0xfe;
        head_byte[cnt++] = (byte) 0xca;

        head_byte[cnt++] = (byte) (((crc) >> 0) & 0xff);
        head_byte[cnt++] = (byte) (((crc) >> 8) & 0xff);
        head_byte[cnt++] = (byte) (((crc) >> 16) & 0xff);
        head_byte[cnt++] = (byte) (((crc) >> 24) & 0xff);

        head_byte[cnt++] = (byte) 0x00;
        head_byte[cnt++] = (byte) 0x00;
        head_byte[cnt++] = (byte) 0x00;
        head_byte[cnt++] = (byte) 0x00;

        head_byte[cnt++] = (byte) 0x02;
        head_byte[cnt++] = (byte) 0x00;
        head_byte[cnt++] = (byte) 0x00;
        head_byte[cnt++] = (byte) 0x00;

        head_byte[cnt++] = (byte) 0x00;
        head_byte[cnt++] = (byte) 0x00;
        head_byte[cnt++] = (byte) 0x00;
        head_byte[cnt++] = (byte) 0x00;

        head_byte[cnt++] = (byte) (((json_byte.length) >> 0) & 0xff);
        head_byte[cnt++] = (byte) (((json_byte.length) >> 8) & 0xff);
        head_byte[cnt++] = (byte) (((json_byte.length) >> 16) & 0xff);
        head_byte[cnt++] = (byte) (((json_byte.length) >> 24) & 0xff);

        return byteMerger(head_byte, json_byte);
    }

    private byte[] makeReportMsg() {
        //把data转换成JSON包到字符
        JSONObject send_ctrl = new JSONObject();
        /*
        "IMEI":"868575020843266"
        "PTY":"hb_pac"
        "ID":"112173300002"
        "CSQ":16
        "ERR":""
        "BL":1
        "BT":""
        "BS":"close"
        "BCC":""
        "BV":""

        "LOC":"E,,N,"
        "IGF":false
        "MVER":"Luat_V0005_Air202"
        "FVER":"1.5.0"

        "BSB":1
        "BSA":0
        "CS":"off"
        */
        String initx = "11217330000";
        String inity = "86857502084326";
        String DEVICE_ID = initx + String.valueOf(id);
        String IMEI = inity + String.valueOf(id);

        send_ctrl.put(SysConstant.REPORT_KEY.MSG_TYPE, "hb_pac");
        send_ctrl.put(SysConstant.REPORT_KEY.DEVICE_ID, DEVICE_ID);
        send_ctrl.put(SysConstant.REPORT_KEY.IMEI, IMEI);


        send_ctrl.put(SysConstant.REPORT_KEY.SIG_QUALITY, 20);
        send_ctrl.put(SysConstant.REPORT_KEY.ERROR_STATUS, "0");
        send_ctrl.put(SysConstant.REPORT_KEY.BATTREY_LEVEL, 97);
        send_ctrl.put(SysConstant.REPORT_KEY.BATTERY_TEMPERATURE, "35");
        send_ctrl.put(SysConstant.REPORT_KEY.BATTERY_STATUS, "");
        send_ctrl.put(SysConstant.REPORT_KEY.BATTERY_CYCLETIME, "close");
        send_ctrl.put(SysConstant.REPORT_KEY.BATTERY_VOLTAGE, "");

        send_ctrl.put(SysConstant.REPORT_KEY.LOCATION, "E,,N,");
        send_ctrl.put(SysConstant.REPORT_KEY.IS_GPSFIX, false);
        send_ctrl.put(SysConstant.REPORT_KEY.M_VERSION, "Luat_V0005_Air202");
        send_ctrl.put(SysConstant.REPORT_KEY.F_VERSION, "1.5.0");
        send_ctrl.put(SysConstant.REPORT_KEY.BATTERY_STATUS_A, 1);
        send_ctrl.put(SysConstant.REPORT_KEY.BATTERY_STATUS_B, 0);
        send_ctrl.put(SysConstant.REPORT_KEY.CHARGE_IN, "off");

        String json_string = send_ctrl.toString();
        byte[] json_byte = new byte[0];
        try {
            json_byte = json_string.getBytes("ASCII");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        int crc = test_makeCrc(json_byte);
        byte[] head_byte = new byte[24];
        int cnt = 0;
        head_byte[cnt++] = (byte) 0xbe;
        head_byte[cnt++] = (byte) 0xba;
        head_byte[cnt++] = (byte) 0xfe;
        head_byte[cnt++] = (byte) 0xca;

        head_byte[cnt++] = (byte) (((crc) >> 0) & 0xff);
        head_byte[cnt++] = (byte) (((crc) >> 8) & 0xff);
        head_byte[cnt++] = (byte) (((crc) >> 16) & 0xff);
        head_byte[cnt++] = (byte) (((crc) >> 24) & 0xff);

        head_byte[cnt++] = (byte) 0x00;
        head_byte[cnt++] = (byte) 0x00;
        head_byte[cnt++] = (byte) 0x00;
        head_byte[cnt++] = (byte) 0x00;

        head_byte[cnt++] = (byte) 0x02;
        head_byte[cnt++] = (byte) 0x00;
        head_byte[cnt++] = (byte) 0x00;
        head_byte[cnt++] = (byte) 0x00;

        head_byte[cnt++] = (byte) 0x00;
        head_byte[cnt++] = (byte) 0x00;
        head_byte[cnt++] = (byte) 0x00;
        head_byte[cnt++] = (byte) 0x00;

        head_byte[cnt++] = (byte) (((json_byte.length) >> 0) & 0xff);
        head_byte[cnt++] = (byte) (((json_byte.length) >> 8) & 0xff);
        head_byte[cnt++] = (byte) (((json_byte.length) >> 16) & 0xff);
        head_byte[cnt++] = (byte) (((json_byte.length) >> 24) & 0xff);
        //System.out.println(crc + " " + "send:id:" + id + " " + DEVICE_ID + " " + IMEI);
        return byteMerger(head_byte, json_byte);
    }

    public static byte[] byteMerger(byte[] byte_1, byte[] byte_2) {
        byte[] byte_3 = new byte[byte_1.length + byte_2.length];
        System.arraycopy(byte_1, 0, byte_3, 0, byte_1.length);
        System.arraycopy(byte_2, 0, byte_3, byte_1.length, byte_2.length);
        return byte_3;
    }

    public JSONObject byte2Json(byte[] buf) {
        String m_payload = null;
        try {
            m_payload = new String(buf, "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        //根据包的类型进行不同的处理
        return JSON.parseObject(m_payload);
    }

    public static int intToint(byte[] buf, int index) {
        int a = (buf[index + 3] << 24) & 0xff000000;
        int b = (buf[index + 2] << 16) & 0x00ff0000;
        int c = (buf[index + 1] << 8) & 0x0000ff00;
        int d = (buf[index + 0]) & 0x000000ff;
        int srcint = a + b + c + d;
        return srcint;
    }
}